package org.colour.amber.rest;

import com.google.common.collect.Lists;
import java.time.LocalDateTime;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.colour.amber.rest.api.CronParseResult;
import org.colour.amber.rest.api.RestResponse;
import org.springframework.http.MediaType;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping(CronRestController.PATH_CRON)
public class CronRestController {

    public static final String PATH_CRON = "/api/v1/cron";

    /**
     * 获取 cron 表达式下次执行时间
     *
     * @param cron cron 表达式字符串
     * @param times 计算下一次执行时间的次数，默认为5次
     * @return 包含 cron 表达式解析结果的响应对象
     * @throws IllegalArgumentException 如果 cron 表达式无效，抛出此异常
     */
    @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public RestResponse<CronParseResult> next(
            @RequestParam String cron, @RequestParam(defaultValue = "5") Integer times) {
        // 验证 cron 表达式的格式
        if (!CronExpression.isValidExpression(cron)) {
            log.error("无效的 cron 表达式: {}", cron);
            throw new IllegalArgumentException("无效的 cron 表达式");
        }

        // 解析 cron 表达式
        CronExpression expression = CronExpression.parse(cron);
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 初始化种子时间为当前时间
        LocalDateTime seed = now;
        // 创建列表存储下一次执行时间
        List<LocalDateTime> nextExecutionTimes = Lists.newArrayList();
        // 循环计算下一次执行时间
        for (int i = 0; i < times; i++) {
            // 计算下一次执行时间
            LocalDateTime nextExecutionTime = expression.next(seed);
            // 如果计算结果为空，则记录错误日志并终止循环
            if (nextExecutionTime == null) {
                log.error("计算出来的下次执行时间为空|cron={}|currentLoopTimes={}|seed={}", cron, i + 1, seed);
                break;
            }
            // 更新种子时间为当前计算出的执行时间，为下一次计算做准备
            seed = nextExecutionTime;
            // 将计算出的执行时间添加到列表中
            nextExecutionTimes.add(nextExecutionTime);
        }
        // 返回包含 cron 表达式解析结果的响应对象
        return RestResponse.success(new CronParseResult(cron, now, nextExecutionTimes));
    }
}
